#include <iostream>
#include <stdio.h>
#include <vector>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
using namespace std;

#define NUM 5

///////////////////////////////////线程及线程控制//////////////////////////////////
// class ThreadData
// {
// public:
//     string thread_name;
// };
// void InitThreadData(ThreadData* td,int number)
// {
//     td->thread_name="thread_"+to_string(number);
// }
// void* threadRoutine(void * args)//注意这个函数，返回值和参数的类型都是void*
// {
//     //pthread_detach(pthread_self());//线程的分离。除了可以在这里设置线程的分离,还可以在主线程那里设置线程的分离
//     //当设置线程为分离状态后，线程执行完毕后系统会自动回收该线程的资源，包括堆栈空间等。、不需要再使用pthread_join来等待线程结束。
//     ThreadData*td=static_cast<ThreadData*>(args);
//     int i=0;
//     while(i<10)
//     {
//         cout<<td->thread_name<<"["<<"tid:"<<pthread_self()<<" "<<"pid:"<<getpid()<<" "
//         <<"ppid"<<getppid()<<"]"<<endl;
//         i++;
//     }
//      delete td;
//     return nullptr;
// }
// int main()
// {
//     vector<pthread_t> vpthread;
//     for(int i=0;i<NUM;i++)
//     {
//         pthread_t tid;//pthread_t类型的线程ID，本质就是一个进程地址空间上的一个地址。
//         ThreadData*td= new ThreadData;
//         InitThreadData(td, i);
//         pthread_create(&tid,nullptr,threadRoutine,td);//线程的创建，第二个参数默认为nullptr
//         vpthread.push_back(tid);
//         sleep(1);
//     }
//     sleep(1);
//     //线程的分离
//     for(const auto& it:vpthread)
//     {
//         pthread_detach(it);
//     }
//     //线程的等待
//     for(size_t i=0;i<NUM;i++)
//     {
//         int n = pthread_join(vpthread[i], nullptr);//正常返回0。错误，它会返回一个非0值.阻塞式的等待
//         printf("n = %d, who = 0x%x, why: %s\n", n, vpthread[i], strerror(n));
//         sleep(1);
//     }

//     //线程的终止与分离
//     //......
//      return 0;
//}
///////////////////////////////////线程的互斥//////////////////////////////////
// 看看为什么要有线程的互斥？下面是一个多线程的抢票逻辑
class threadData
{
public:
    threadData(int number)
    {
        threadname = "thread-" + to_string(number);
    }

public:
    string threadname;
};

int ticket = 1000;

void *route(void *args)
{
    threadData *td = static_cast<threadData *>(args); // 强制类型转换和（threadData*）args一样，只是这样写更优雅
    // pthread_detach(pthread_self());
    const char *name = td->threadname.c_str();
    while (true)
    {
        if (ticket > 0)
        {
            usleep(1000);//模拟漫长业务的过程(信息填写)，在这个漫长的业务过程中，可能有很多个线程会进入该代码段
            printf("who=%s, get a ticket: %d\n", name, ticket); // ?
            ticket--;
        }
        else
            break;
    }
    printf("%s ... quit\n", name);
    return nullptr;
}

int main(void)
{
    vector<pthread_t> tids;
    for (int i = 0; i < NUM; i++)
    {
        pthread_t tid;
        threadData *td = new threadData(i);
        pthread_create(&tid, NULL, route, td);
        tids.push_back(tid);
    }

    for(const auto&it:tids)
    {
        pthread_detach(it);
    }
    return 0;
}